package cn.microservices.cloud.gateway.interpector.rquest;


import cn.microservices.cloud.gateway.util.Md5Util;
import cn.microservices.cloud.gateway.util.WebFluxUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Pattern;


/**
 * 请求一次的拦截 once+timestamp
 */
@Component
@RefreshScope
public class OnceRequestInterceptor {

    private Logger log = LoggerFactory.getLogger(getClass());
    private final int PERMIT_LEAST_TIME = 1000 * 60 * 1;
    private final int MAX_UUID_COUNT = 60;
    private final String TIMESTAMP_PARAM = "timestamp";
    private final String ONCE_PARAM = "once";
    private final String UUID_PARAMS = "mobileNo";
    private final String SIGN_PARAM = "sign";
    private final String VERSION_PARAM = "version";
    private final Pattern pattern = Pattern.compile("\\d+");
    private final Map<String, String> onceCacheMap = new ConcurrentHashMap<>();
    @Value("${deviceVersion:1.0.0}")
    private String deviceVersion;


    /**
     * 判断请求是无效
     *
     * @param request 客户端的请求
     * @return true 无效 false 有效
     */
    public boolean isInvalid(ServerHttpRequest request) {
        try {
            String version = request.getHeaders().getFirst(VERSION_PARAM);

            //version(低版本允许通过)
            if (version == null || deviceVersion.compareToIgnoreCase(version) > 0) {
                log.warn("Ip={} 方法={} 版本={} 允许通过",
                        WebFluxUtil.getRealIp(request), request.getURI(), version);
                return false;
            }


            String onceStr = request.getHeaders().getFirst(ONCE_PARAM);

            String timestampStr = request.getHeaders().getFirst(TIMESTAMP_PARAM);

            String signStr = request.getHeaders().getFirst(SIGN_PARAM);

            String uuidStr = request.getHeaders().getFirst(UUID_PARAMS);


            if ((StringUtils.isEmpty(onceStr) || StringUtils.isEmpty(timestampStr)
                    || StringUtils.isEmpty(signStr))
                    || !pattern.matcher(timestampStr).matches()) {
                log.warn("once={} timestamp={} sign={}  所传入参数不符合规范"
                        , onceStr, timestampStr, signStr);
                return true;
            }


            //once
            if (onceCacheMap.get(onceStr) != null) {
                log.warn("once={}已经被使用过,不给予通过", onceStr);
                return true;
            }


            //timestamp--处理时间戳
            Long interval = System.currentTimeMillis() - Long.parseLong(timestampStr) * 1000;
            //判断时间是否超过规定时间
            if (interval > PERMIT_LEAST_TIME) {
                log.warn("传入时间差={}大于允许时间差={} 不给予通过", timestampStr, PERMIT_LEAST_TIME);
                return true;
            }


            //sign
            //加密比对 mobileNo+时间戳+once
            String signEncrypt = Md5Util.md5(uuidStr + timestampStr + onceStr);
            if (!signStr.equals(signEncrypt)) {
                log.warn("用户所传的sign={}与加密后sign={}的不正确,不给予通过", signStr, signEncrypt);
                return true;
            }

            log.info("Ip={} once={} ,请求={} 验证通过", WebFluxUtil.getRealIp(request), onceStr
                    , request.getURI());


            //达到最大值，初始化数据
            if (onceCacheMap.size() >= MAX_UUID_COUNT) {
                onceCacheMap.clear();
            }

            onceCacheMap.put(onceStr, uuidStr);


        } catch (Exception e) {

            log.error("请求过期拦截出错,进行降级处理", e);

        }

        return false;
    }

}
